令和なのに NAT インスタンスを手作りして使ってみた
昔は NAT Gateway なんて便利なものはなかったんじゃよ
コンバンハ、千葉(幸)です。
先日、むかしを懐かしむ機会がありました。2016 年 1 月の ACM の登場までは IAM に証明書をアップロードしていた、という内容です。
ほぼ時期を同じくして「いまではそれを使うのが当たり前」となっているサービスが登場したな、ということで思い返されたのは 2015 年 12 月に登場した NAT Gateway です。
NAT Gateway が登場するまではみんな EC2 で NAT インスタンスを構築して使っていました。NAT インスタンス用の AMI が提供されていたので、それをそのまま使うケースが多かったかと思います。
久しぶりに NAT インスタンスのドキュメントを確認すると Linux インスタンスを NAT インスタンス化する手順が載っていたので、今回はそれを試してみます。
言うほど NAT インスタンスを使うのは「ナシ」なのか
「いまでは NAT Gateway を使うのが当たり前」という論調でここまで喋ってきましたが、NAT インスタンスを採用するのはそこまでアンチパターンなのでしょうか。
わたしとしては、積極的にオススメはしないものの「ACM でなく IAM で証明書を管理する」ほどの「ナシ」度ではないと考えています。
NAT Gateway と NAT インスタンスの比較の観点は以下にまとまっています。
いろいろ書いてありますが、簡単に言えば「NAT Gateway の方が料金が高い代わりにいろいろマネジージドでやってくれる」という考え方です。
コストを比較してみます。かなり決めうちで以下条件で試算しました。
- 東京リージョン
- NAT インスタンスは以下構成
- Amazon Linux2 で t3.micro
- EBS は gp3 で 8 GiB
- 停止しない運用とする
- データの通信先はインターネットのみで 100 GB
1ヶ月を 720 時間として考えると月額料金(USD)は以下のようになります。 *1
ゲートウェイ | インスタンス | |
---|---|---|
デバイス | 44.64 | 9.79 |
ストレージ | - | 0.77 |
データ処理 | 6.20(※) | - |
データ転送 | 11.40 | 11.40 |
合計 | 62.24 | 21.96 |
(※)データ処理は 100 GB の前提で計算していますが、戻りの通信も課金対象であるため実際にはもっと増えるはずです。
NAT Gateway は利用期間に応じた単価が高いのと、データ処理量に応じた料金が発生します。NAT インスタンスは、使わない時間は停止することでオンデマンド料金をさらに減らせます。
大抵の場合、NAT インスタンスの方がコストは安くつきます。
このコストの差を鑑みてもなお 本番環境では NAT Gateway の採用をお勧めします。 NAT Gateway がマネージドでやってくれる部分や性能のメリットの方が大きいと考えるためです。検証環境や、万が一インターネットへのアウトバウンドが途切れてもクリティカルなことにはならない、というワークロードであればコスト抑制をモチベーションに NAT インスタンスを採用するのもアリだと思います。
それぞれの料金の以下をご参照ください。
- 料金 - Amazon VPC | AWS
- オンデマンドインスタンスの料金 - Amazon EC2 (仮想サーバー) | AWS
- ハイパフォーマンスブロックストレージの料金 – Amazon EBS の料金 – Amazon Web Services
個人の検証環境で使う分には便利じゃない?
はい、めっちゃ便利だと思います。
NAT インスタンスの構成を作ってみた
今回は以下の構成を作成していきます。
最終的に、プライベートサブネットにあるクライアントインスタンスに SSM セッションマネージャーで接続できるところをゴールとします。
(セッションマネージャー接続できるためにはクライアントインスタンスから専用のエンドポイントに疎通できる必要がある。VPC エンドポイントが無い構成なのでインターネットゲートウェイ経由で接続できる必要がある。)
0. NAT インスタンスの作成(前置き)
作成は以下ページを参考にします。
ページには以下の注意書きがあります。
重要
NAT AMI は、2020 年 12 月 31 日に標準サポートが終了した Amazon Linux の最新バージョン 2018.03 に基づいて構築されています。詳細については、ブログ投稿「Amazon Linux AMI のサポート終了」を参照してください。この AMI は、重要なセキュリティ更新だけを受け取ります (定期的な更新はありません)。
既存の NAT AMI を使用する場合は、AWS が NATゲートウェイに移行することを推奨します。NAT ゲートウェイでは、可用性と帯域幅に優れ、運用管理の手間を軽減できます。NAT インスタンスがユースケースに合致している場合は、独自の NAT AMI を作成できます。詳細については、「NAT ゲートウェイと NAT インスタンスの比較」を参照してください。
標準で用意されている NAT AMI は、2 ではない Amazon Linux をベースにしています。そのため、それをそのまま使用するのは避けるべきであり、いまから NAT インスタンスを利用するのであれば独自に作成する必要があります。
親切なことにセットアップ用のコマンドをドキュメントに記載してくれています。 *2
sudo sysctl -w net.ipv4.ip_forward=1 sudo /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE sudo yum install iptables-services sudo service iptables save
前はこんな記述なかったよな……?と思い調べたところ、2021年9月にドキュメントに追記されていました
1. NAT インスタンスの作成
以下の条件で EC2 インスタンスを作成しました。作成の詳細は割愛します。
- amzn2-ami-kernel-5.10-hvm-2.0.20221004.0-x86_64-gp2(
ami-0de5311b2a443fb89
) - パブリックサブネットに配置しパブリックIP 割り当て
- t3.micro、gp3、8 GiB
- IAM ロールを割り当て Systems Manager の権限付与
- SecuriryGroup
- インバウンド:後続の手順で作成するクライアント用インスタンスからのすべてのトラフィック
- アウトバウンド:0.0.0.0/0 へのすべてのトラフィック
作成したインスタンスに SSM セッションマネージャーで接続し、先ほど確認したコマンドをベースに実行していきます。
IP フォワードの有効化を永続的に実施。
sh-4.2$ sudo sysctl -w net.ipv4.ip_forward=1 | sudo tee -a /etc/sysctl.conf net.ipv4.ip_forward = 1
Iptablesでの NAT の設定。
sh-4.2$ sudo /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
(せっかくなのでテーブルの中身を確認)
sh-4.2$ sudo iptables -t nat --list Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- anywhere anywhere
Iptables で設定した内容は再起動でクリアされるので、永続化するためにiptables-services
を導入。
sh-4.2$ sudo yum install iptables-services Loaded plugins: extras_suggestions, langpacks, priorities, update-motd Resolving Dependencies --> Running transaction check ---> Package iptables-services.x86_64 0:1.8.4-10.amzn2.1.2 will be installed --> Finished Dependency Resolution Dependencies Resolved ======================================================================================================================================== Package Arch Version Repository Size ======================================================================================================================================== Installing: iptables-services x86_64 1.8.4-10.amzn2.1.2 amzn2-core 58 k Transaction Summary ======================================================================================================================================== Install 1 Package Total download size: 58 k Installed size: 24 k Is this ok [y/d/N]: y Downloading packages: iptables-services-1.8.4-10.amzn2.1.2.x86_64.rpm | 58 kB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : iptables-services-1.8.4-10.amzn2.1.2.x86_64 1/1 Verifying : iptables-services-1.8.4-10.amzn2.1.2.x86_64 1/1 Installed: iptables-services.x86_64 0:1.8.4-10.amzn2.1.2 Complete!
保存を実行します。
sh-4.2$ sudo service iptables save iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]
iptables の自動起動を有効化します。
sh-4.2$ sudo systemctl enable iptables Created symlink from /etc/systemd/system/basic.target.wants/iptables.service to /usr/lib/systemd/system/iptables.service.
これで OS 上のセットアップが完了しました。
1.a NAT インスタンスの再起動後の設定確認
手順として必要なわけではないですが、上記の手順で設定した内容が再起動によってクリアされないかを確認しておきます。
再起動してから接続し、各種設定を確認します。
net.ipv4.ip_forward
が1
であること。
sh-4.2$ sysctl -n net.ipv4.ip_forward 1
iptables
が起動していること。
sh-4.2$ systemctl status iptables ● iptables.service - IPv4 firewall with iptables Loaded: loaded (/usr/lib/systemd/system/iptables.service; enabled; vendor preset: disabled) Active: active (exited) since Mon 2022-11-07 12:05:58 UTC; 4min 33s ago Process: 1770 ExecStart=/usr/libexec/iptables/iptables.init start (code=exited, status=0/SUCCESS) Main PID: 1770 (code=exited, status=0/SUCCESS) CGroup: /system.slice/iptables.service
iptables の nat テーブルの値が設定した通りであること。
sh-4.2$ sudo iptables -t nat --list Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- anywhere anywhere
大丈夫そうですね!
2. NAT インスタンスの送信元/送信先チェックの無効化
EC2 インスタンス用の ENI はデフォルトで送信元/送信先チェック属性(SrcDestCheck
)が有効になっています。有効な場合、自身が送信元/送信先でないトラフィックを破棄する挙動となるので、NAT インスタンスの場合は無効化してあげる必要があります。
「アクション」→「ネットワーキング」→「ソース/宛先チェックを変更」を選択します。
「停止」にチェックをつけ、「保存」を押下します。
ステータスはインスタンスの詳細画面のうち、「ネットワーキング」タブから確認できます。
3. クライアントインスタンスのサブネットルートテーブルの変更
このあとクライアントインスタンスを作成する先のサブネットのルートテーブルを編集します。
送信先を0.0.0.0/0
とし、ターゲットを NAT インスタンスとしたルートを追加します。同じ VPC にあるインスタンスが候補として出てくるので選択するのは簡単です。
ちなみに、変更が保存されると自動的にターゲットが NAT インスタンスの ENI に置き換わっていました。(はじめから ENI をターゲットとしてルート編集することも可能です。)
4. クライアントインスタンスの作成
以下設定で作成しました。詳細な手順は割愛します。
- amzn2-ami-kernel-5.10-hvm-2.0.20221004.0-x86_64-gp2(
ami-0de5311b2a443fb89
) - 先ほどルートテーブルを編集したプライベートサブネットに配置
- t3.micro、gp3、8 GiB
- IAM ロールを割り当て Systems Manager の権限付与
- SecuriryGroup
- インバウンド:なし
- アウトバウンド:0.0.0.0/0 へのすべてのトラフィック
5. クライアントインスタンスからの疎通確認
クライアントインスタンスに対してセッションマネージャー接続を試みます。
問題なく接続が完了しました。また、checkip.amazonaws.com
への curl も成功し、NAT インスタンスが持つパブリック IP アドレスが返却されました。
NAT インスタンスが正常に機能していることが確認できました。
コストを取るかマネージドのメリットを取るか
NAT インスタンスを Amazon Linux2 の AMI から手作りで作ってみました。
NAT Gateway に比べればランニングコストは安い(ことが大抵の場合 期待できる)ですが、何かあった時に復旧作業するのに動く人のコストは?パッチ適用などを継続的に行うための運用コストは?などを考えると、マネージドの方に寄せたほうが嬉しいことが多い気がします。
何かあっても別に困らない、開発環境だし運用らしい運用も別にしないからランニングコストを低いことを優先する、といったワークロードでは採用してみるのもいいかもしれません。
以上、 チバユキ (@batchicchi) がお送りしました。
あわせて読みたい
参考
- Linuxで作るファイアウォール[NAT設定編]:ゼロから始めるLinuxセキュリティ(4)(1/2 ページ) - @IT
- natテーブルを利用したLinuxルータの作成:習うより慣れろ! iptablesテンプレート集(2)(1/6 ページ) - @IT